package net.liteheaven.diagnose;

import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * Created by LiangYu on 2017/6/2.
 */
public class DiagnoseController {

    private static final int THRESHOLD = 5;
    private static DiagnoseController instance;
    private DiagnoseOutputListener outputListener;
    private DiagnoseStateListener stateListener;
    private Handler handler;
    private int failedCount = 0;

    public static DiagnoseController inst(){
        if (instance == null){
            instance = new DiagnoseController();
        }
        return instance;
    }

    private DiagnoseController(){
        handler = new Handler(Looper.getMainLooper());
    }

    public void setOutputListener(DiagnoseOutputListener listener){
        this.outputListener = listener;
    }

    public void setStateListener(DiagnoseStateListener listener){
        this.stateListener = listener;
    }

    private void dispatchOutput(final String output){
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (outputListener != null){
                    outputListener.onOutput(output);
                }
            }
        });
    }

    private void dispatchState(final boolean state){
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (stateListener != null){
                    stateListener.onState(state);
                }
            }
        });
    }

    public void reportRequestResult(boolean success){
        if (success){
            dispatchOutput("clear failed count while success.");
            failedCount = 0;
        }else{
            failedCount++;
            dispatchOutput("failed count increased.");
            if (failedCount >= THRESHOLD){
                dispatchOutput("failed count reached threshold.");
                failedCount = 0;
                checkStatus();
            }
        }

        dispatchOutput("failed count = " + failedCount);
    }

    /**
     * 当达到错误数目时，检查网络状态
     */
    public void checkStatus(){
        dispatchOutput("start check state ...");
        new AsyncTask<Void, Void, Boolean>(){

            @Override
            protected Boolean doInBackground(Void... params) {
                boolean result;
                if (false){
                    result = checkConnecting();
                }else{
                    result = checkDns();
                }
                dispatchOutput("check state result = " + result);
                return result;
            }

            @Override
            protected void onPostExecute(Boolean result) {
                super.onPostExecute(result);
                dispatchState(result);
            }
        }.executeOnExecutor(Executors.newCachedThreadPool());

    }

    /**
     * 检查连接
     * 这种方式有个问题，就是连上无用的wifi时，超时时间依然很长，时间都花在DNS解析上面了，所以废弃
     * @return
     */
    @Deprecated
    private boolean checkConnecting(){
        try{
            URL url = new URL("https://www.qq.com");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(1000);
            connection.setReadTimeout(1000);
            connection.connect();
            dispatchOutput("response code = " + connection.getResponseCode());
        }catch (Exception e){
            dispatchOutput(e.toString());
            return false;
        }
        return true;
    }

    /**
     * 根据DNS获取IP，根据这种方式判断网络连接
     * @return
     */
    private boolean checkDns() {
        try {
            DnsResolver dnsRes = new DnsResolver("114.114.114.114");
            //DnsResolver dnsRes = new DnsResolver("www.qq.com");
            Future<Boolean> future = Executors.newCachedThreadPool().submit(dnsRes);
            Boolean result = future.get(3, TimeUnit.SECONDS);
            return result;
        } catch (Exception e) {
            dispatchOutput(e.toString());
            return false;
        }
    }

    private class DnsResolver implements Callable<Boolean> {

        private String domain;

        public DnsResolver(String domain) {
            this.domain = domain;
        }

        @Override
        public Boolean call() throws Exception {
            boolean result = false;
            try {
                Process p = Runtime.getRuntime().exec("ping -c 1 -w 5 " + domain);

                InputStream input = p.getInputStream();
                BufferedReader in = new BufferedReader(new InputStreamReader(input));
                StringBuffer stringBuffer = new StringBuffer();
                String content;
                while ((content = in.readLine()) != null) {
                    stringBuffer.append(content);
                }
                dispatchOutput("content = " + stringBuffer);

                int status = p.waitFor();
                dispatchOutput("waitFor result = " + status);
                if (status == 0){
                    result = true;
                }
            } catch (Exception e) {
            }

            return result;
        }
    }
}
